/* Copyright (c) 2001 Nextel Communications, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *   - Neither the name of Nextel Communications, Inc. nor the names of its
 *     contributors may be used to endorse or promote products derived from
 *     this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NEXTEL
 * COMMUNICATIONS, INC. OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.nextel.ui; // Generated package name

import com.nextel.ui.custom.OListenerScroll;
import javax.microedition.lcdui.Graphics;
import pe.com.nextel.util.ArrayList;
import pe.com.nextel.util.Iterator;
import pe.com.nextel.util.List;

/**
 *  An helper for implementing {@link com.nextel.ui.OContainer OContainer}.
 *
 */
class OContainerHelper implements OContainer {
    
    /** A value is currently undefined, for instance if the user of this adapter
     * has not overridden getHeight or getWidth **/
    public final static int UNDEFINED = -1;
    // assume nominal 6 components
    private List componentItems ;
    // all components in the container need to be painted
    private boolean needsRepaint = true;
//    private boolean pintar = true;
    private OCompositeScreen screen;
    private int actualComponent = 0;
    
    /** <b>NOTE: can accomodate a maximum of 50 rows</b> **/
//    private int [] rowHeights = new int [ 50 ];
    /**
     * Creates a new <code>OContainerHelper</code> instance.
     */
    public OContainerHelper() {
    } // OContainerHelper
    
    /**
     * Creates a new <code>OContainerHelper</code> instance.
     *
     * @param screen The screen that contains this container.
     */
    public OContainerHelper(OCompositeScreen screen) {
        this();
        this.screen = screen;
    } // OContainerHelper
    
    void add(OContainerItem item) {
        
        if(componentItems == null) componentItems = new ArrayList();
        componentItems.add(item);
        
    } // add
    
    void add(OComponent component) {
        if(componentItems == null) componentItems = new ArrayList();
        componentItems.add(component);
        
    } // add
    
    void remove(OComponent ocomponent) {
        
        for (int i = 0; componentItems != null && i < componentItems.size(); i++) {
            if(ocomponent == (OComponent) componentItems.get(i))
                componentItems.remove(i);
        }
        
    }
    
    void remove(int index) {
        //if ( Debug.ON ) Logger.dev( "OContainerHelper.add1 ENTERED" );
        if(componentItems!= null)componentItems.remove(index);
        // if ( Debug.ON ) Logger.dev( "OContainerHelper.add1 EXITTING" );
    }
    
    /**
     * Gets the component of the specified rank.
     *
     * @param rank Rank of the desired component.
     * @return a <code>OFocusableComponent</code> value
     */
    public OComponent getComponent(int rank) {
        Object obj = componentItems != null ?  componentItems.get(rank):null;
        return (obj == null ? null : (OComponent) obj);
    } // getComponent
    
    /**
     * Resets the container to it's state after all components were added.
     * Specifically, the first component in the container will have focus.
     *
     */
    public int getComponentCount() {
        return componentItems != null ? componentItems.size():0;
    }
    
    /**
     * Gets the components in the container.
     *
     * @return an <code>OComponent[]</code> value
     */
    public OComponent[] getComponents() {
        if (componentItems != null) {
            OComponent[] returnVal = new OComponent[componentItems.size()];
            int idx = 0;
            for (Iterator items = componentItems.iterator();
            items.hasNext();) {
                Object item = items.next();
                if (item instanceof OComponent) {
                    returnVal[idx] = (OComponent) item;
                } else // item instanceof OContainerItem
                {
                    returnVal[idx] = ((OContainerItem) item).component;
                }
                idx++;
            }
            return returnVal;
        }
        return null;
    } // getComponents
    
    Iterator getItems() {
        return componentItems != null ?componentItems.iterator():null;
    } // getItems
    
    public OCompositeScreen getScreen() {
        return this.screen;
    } // getScreen
    
    public void setScreen(OCompositeScreen screen) {
        this.screen = screen;
    } // setScreen
    
    public void paint(Graphics g) {
//        System.out.println("OContainerHelper.paint ENTERED");
//        if(pintar){
//        OFocusableComponent focusedComponent = null;
        //componentItems
        for (int x = 0; componentItems != null && x < componentItems.size(); x++) {
            OComponent component = ((OContainerItem) componentItems.get(x)).component;
            paintComponent(g, component);
        }
        
        // Although we've already painted the focused component, we want paint it
        // painted last so that if it
        // overwrites the display areas of any other components - as may happen
        // if, for example, the focused component is a pop-up list - its
        // overwriting of those component(s) is not then undone by the painting of
        // the overwritten components. So we repaint it one final time.
        OFocusableComponent last = this.screen.getFocusManager().getFocused();
        if (last != null) {
            last.setNeedsRepaint(true);
            paintComponent(g, last);
        }
        
        actualComponent = 0;
//    }
        
//        if ( Debug.ON ) Logger.dev( "OContainerHelper.paint EXITTING" );
        
    } // paint
    
    public void paint(Graphics g, boolean all) {
//        if (Debug.ON) {
//            System.out.println("OContainerHelper.paint ENTERED");
//        }
        
        needsRepaint = all;
        
        paint(g);
        
        needsRepaint = false;
        
    } // paint
    
    protected void paintComponent(Graphics g, OComponent component) {
//        System.out.println("OContainerHelper.paintComponent ENTERED");
        
        if (screen != null && component != null) {
            
            int bodyY = screen.getBodyRow() + screen.getBodyOffset();
            
            if (component != null && screen != null && component.getY() + component.getHeight() >= bodyY &&
                    component.getY() <= bodyY + screen.getBodyHeight()) { // component is at least partially within viewport, so display it
                if (!(component instanceof OContainer)) {
                    
                    if (needsRepaint || component.needsRepaint()) {
                        
                        component.paint(g, screen.getBodyOffset());
                        component.setNeedsRepaint(false);
                    }
                } else // component is also a container
                {
                    OComponent[] components = ((OContainer) component).getComponents();
                    for (int idx = 0; components != null && idx < components.length; idx++) { // recurse
                        if (components[idx] != null) {
                            paintComponent(g, components[idx]);
                        }
                    }
                    components = null;
                    System.gc();
                }
            }
        }
//        if ( Debug.ON ) Logger.dev( "OContainerHelper.paintComponent EXITTING" );
    } // paintComponent
    
    public int getHeight() {
        // we currently calculate the height each time. if/when the framework is
        // rearchitected so that the container knows when it's been laid out,
        // highest-value for the
        // coordinate of the
        int height = 0;
        OComponent[] components = getComponents();
        OComponent thisOne = null;
        for (int idx = 0; components != null && idx < components.length; idx++) {
            thisOne = components[idx];
            height = Math.max(height, thisOne.getY() + thisOne.getHeight());
        }
        components = null;
        
        System.gc();
        return height - screen.getBodyRow();
    } // getHeight
    
    /**
     * Returns the width of the container.
     *
     * @return {@link #UNDEFINED UNDEFINED} is returned until the container
     * has been added to a screen, after which the screen width is returned.
     */
    public int getWidth() {
        int width = 0;
        OComponent[] components = getComponents();
        for (int idx = 0; components != null && idx < components.length; idx++) {
            OComponent thisOne = components[idx];
            width = Math.max(width, thisOne.getY() + thisOne.getWidth());
        }
        components = null;
        System.gc();
        return width;
    } // getWidth
    
    public void clearAll() {
//        pintar = false;
        needsRepaint = false;
        
        if (componentItems != null) {
            componentItems.clear();
            componentItems = null;
        }
        
        screen = null;
        
        System.gc();
    }
    
    /**
     * Processes a key press.
     * <p>
     * if the key pressed is the right or left key focus is changed appropriately.
     * All other keys are passed to the component which currently has focus.
     *
     * @param keyCode Code of the key pressed.
     */
    public void keyPressed(int keyCode) {
        
        if(componentItems != null && componentItems.size() > actualComponent){
            
            OComponent component = ((OContainerItem) componentItems.get(actualComponent)).component ;
            
            if(screen.getBodyHeight() > component.getHeight() + component.getY()){
                actualComponent ++;
                if(componentItems.size() > actualComponent)
                    component = ((OContainerItem) componentItems.get(actualComponent)).component  ;
            }
            
            
            if (screen.getBodyHeight() < component.getHeight() + component.getY()) {
                //            System.out.println("es menor" + component);
                if (component instanceof OListenerScroll ) {
                    //                 System.out.println("es component" + keyCode);
                    ((OListenerScroll) component).addPosicionTravers(keyCode);
                    
                }
            }
        }
    } // keyPressed
}// OContainerHelper

